package com.apobates.forum.toro.tuple;

import com.apobates.forum.toro.tuple.strategy.TripleSupplyFutureStrategy;
import com.apobates.forum.toro.tuple.strategy.TripleSupplyStrategy;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 左对象是单实例的Triple映射执行器
 * 左对象与右对象一对一模式的执行器
 * @param <L> 左对象类型
 * @since 20220827
 * @author xiaofanku@live.cn
 */
public class TripleMapperExecutor<L> {
    private final Supplier<L> leftObjFun;
    private final Map<String,String> arguments;
    private static final Logger logger = LoggerFactory.getLogger(PairMapperExecutor.class);

    public TripleMapperExecutor(Supplier<L> leftObjFun, Map<String, String> arguments) {
        this.leftObjFun = leftObjFun;
        this.arguments = arguments;
    }

    /**
     *
     * @param consumer
     * @return
     * @param <M>
     * @param <R>
     */
    public <M,R> Builder<M,R, Triple<L, M, R>> consume(Consumer<Triple<L, M, R>> consumer){
        TripleResultMapperTransfer<L,M,R,Triple<L, M, R>> transfer = new TripleResultMapperTransfer<>(){
            @Override
            public Consumer<Triple<L, M, R>> getConsumer() {
                return consumer;
            }
            @Override
            public Function<Triple<L, M, R>, Triple<L, M, R>> getFormater() {
                return Function.identity();
            }
        };
        return new Builder<>(transfer);
    }

    /**
     *
     * @param formater
     * @return
     * @param <M>
     * @param <R>
     * @param <F>
     */
    public <M,R,F> Builder<M,R,F> format(Function<Triple<L, M, R>,F> formater){
        TripleResultMapperTransfer<L,M,R,F> transfer = new TripleResultMapperTransfer<>(){
            @Override
            public Consumer<Triple<L, M, R>> getConsumer() {
                return (Triple<L, M, R> ins)->logger.info("TripleMapperExecutor Default Consumer");
            }
            @Override
            public Function<Triple<L, M, R>, F> getFormater() {
                return formater;
            }
        };
        return new Builder<>(transfer);
    }

    /**
     *
     * @param transfer
     * @return
     * @param <M>
     * @param <R>
     * @param <F>
     */
    public <M,R,F> Builder<M,R,F> transfer(TripleResultMapperTransfer<L,M,R,F> transfer){
        return new Builder<>(transfer);
    }

    public Supplier<L> getLeftObjFun() {
        return leftObjFun;
    }
    public Map<String, String> getArguments() {
        return arguments;
    }

    /**
     * 使用内置的TripleSupplyFutureStrategy异步策略返回执行结果
     * @param middleFun 中对象查询函数
     * @param rightFun 右对象查询函数
     * @return
     * @param <M> 中对象类型
     * @param <R> 右对象类型
     * @param <E> 中函数的参数类型
     * @param <U> 右函数的参数类型
     */
    public <M,R,E,U> Triple<L,M,R> get(Function<E, M> middleFun, Function<U, R> rightFun) {
        return this.get(middleFun, rightFun, new TripleSupplyFutureStrategy<>());
    }

    /**
     * 使用指定聚合策略返回执行结果
     * @param middleFun 中对象查询函数
     * @param rightFun 右对象查询函数
     * @param strategy 聚合策略
     * @return
     * @param <M> 中对象类型
     * @param <R> 右对象类型
     * @param <E> 中函数的参数类型
     * @param <U> 右函数的参数类型
     */
    public <M,R,E,U> Triple<L,M,R> get(Function<E, M> middleFun, Function<U, R> rightFun, TripleSupplyStrategy<L,M,R,E,U> strategy) {
        return strategy.apply(getLeftObjFun(), middleFun, rightFun, getArguments());
    }

    public class Builder<M,R,F>{
        private final TripleResultMapperTransfer<L,M,R,F> transfer;

        private Builder(TripleResultMapperTransfer<L,M,R,F> transfer){
            this.transfer = transfer;
        }

        /**
         *
         * @param middleFun
         * @param rightFun
         * @return
         * @param <E>
         * @param <U>
         */
        public <E,U> F get(Function<E, M> middleFun, Function<U, R> rightFun){
            Triple<L,M,R> triple = TripleMapperExecutor.this.get(middleFun, rightFun);
            return this.transfer.get(triple);
        }

        /**
         *
         * @param middleFun
         * @param rightFun
         * @param strategy
         * @return
         * @param <E>
         * @param <U>
         */
        public <E,U> F get(Function<E, M> middleFun, Function<U, R> rightFun, TripleSupplyStrategy<L,M,R,E,U> strategy){
            Triple<L,M,R> triple = TripleMapperExecutor.this.get(middleFun, rightFun, strategy);
            return this.transfer.get(triple);
        }
    }
}
